package com.harmony.pilot.knowledge.service;

import com.google.gson.Gson;
import com.harmony.pilot.knowledge.entity.*;
import com.harmony.pilot.knowledge.repository.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * GN构建目标和源文件映射服务
 * 建立BUILD.gn中的target与其包含的源文件(.h/.cpp)的对应关系
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GnSourceMappingService {
    
    private final GnSourceMappingRepository mappingRepository;
    private final GnTargetRepository gnTargetRepository;
    private final GnBuildFileRepository gnBuildFileRepository;
    private final FileMetadataRepository fileMetadataRepository;
    private final Gson gson = new Gson();
    
    @Value("${openharmony.code.base-path:../ohcode}")
    private String codeBasePath;
    
    /**
     * 为GN target建立源文件映射
     */
    @Transactional
    public void buildMappingForGnTarget(GnTarget target, GnBuildFile gnBuildFile) {
        log.debug("Building mapping for GN target: {}", target.getTargetName());
        
        // 解析sources列表
        List<String> sources = parseJsonList(target.getSources());
        
        for (String source : sources) {
            // 构建源文件的绝对路径
            Path gnFileDir = Paths.get(gnBuildFile.getFilePath()).getParent();
            Path sourcePath = gnFileDir.resolve(source).normalize();
            
            // 确定源文件类型
            String sourceType = determineSourceType(source);
            
            // 创建映射
            GnSourceMapping mapping = new GnSourceMapping();
            mapping.setGnTargetId(target.getId());
            mapping.setSourceFilePath(source);
            mapping.setSourceFileAbsolutePath(sourcePath.toString());
            mapping.setSourceType(sourceType);
            mapping.setGnFilePath(gnBuildFile.getFilePath());
            mapping.setTargetName(target.getTargetName());
            mapping.setModuleName(gnBuildFile.getModuleName());
            
            // 检查是否已存在
            Optional<GnSourceMapping> existing = mappingRepository
                    .findByGnTargetIdAndSourceFilePath(target.getId(), source);
            
            if (existing.isEmpty()) {
                mappingRepository.save(mapping);
            }
        }
    }
    
    /**
     * 为所有GN target建立映射
     */
    @Transactional
    public void buildAllMappings() {
        log.info("Building all GN source mappings...");
        
        List<GnBuildFile> gnFiles = gnBuildFileRepository.findAll();
        
        for (GnBuildFile gnFile : gnFiles) {
            for (GnTarget target : gnFile.getTargets()) {
                buildMappingForGnTarget(target, gnFile);
            }
        }
        
        log.info("GN source mapping completed");
    }
    
    /**
     * 根据源文件查找所属的GN target
     */
    public List<GnSourceMapping> findGnTargetsBySourceFile(String sourceFilePath) {
        return mappingRepository.findBySourceFilePath(sourceFilePath);
    }
    
    /**
     * 根据GN target查找包含的源文件
     */
    public List<GnSourceMapping> findSourceFilesByGnTarget(Long gnTargetId) {
        return mappingRepository.findByGnTargetId(gnTargetId);
    }
    
    /**
     * 验证源文件是否在对应的GN target中
     */
    public boolean isSourceFileInGnTarget(String sourceFilePath, Long gnTargetId) {
        return mappingRepository.existsByGnTargetIdAndSourceFilePath(gnTargetId, sourceFilePath);
    }
    
    /**
     * 查找缺失的源文件映射（源文件存在但未在GN中声明）
     */
    public List<String> findMissingSourceFiles(Long gnTargetId, String gnFilePath) {
        List<String> missingFiles = new ArrayList<>();
        
        // 获取GN target的所有源文件
        List<GnSourceMapping> mappings = findSourceFilesByGnTarget(gnTargetId);
        Set<String> declaredSources = mappings.stream()
                .map(GnSourceMapping::getSourceFilePath)
                .collect(Collectors.toSet());
        
        // 查找目录下的所有.h/.cpp文件
        Path gnFileDir = Paths.get(gnFilePath).getParent();
        try {
            java.nio.file.Files.walk(gnFileDir, 3)
                    .filter(java.nio.file.Files::isRegularFile)
                    .filter(path -> {
                        String fileName = path.getFileName().toString();
                        return fileName.endsWith(".h") || fileName.endsWith(".hpp") ||
                               fileName.endsWith(".cpp") || fileName.endsWith(".cc") ||
                               fileName.endsWith(".c");
                    })
                    .forEach(path -> {
                        String relativePath = gnFileDir.relativize(path).toString().replace("\\", "/");
                        if (!declaredSources.contains(relativePath)) {
                            missingFiles.add(relativePath);
                        }
                    });
        } catch (Exception e) {
            log.error("Failed to find missing source files", e);
        }
        
        return missingFiles;
    }
    
    /**
     * 确定源文件类型
     */
    private String determineSourceType(String filePath) {
        String lower = filePath.toLowerCase();
        if (lower.endsWith(".h") || lower.endsWith(".hpp")) {
            return "HEADER";
        } else if (lower.endsWith(".cpp") || lower.endsWith(".cc") || lower.endsWith(".c")) {
            return "SOURCE";
        }
        return "UNKNOWN";
    }
    
    /**
     * 解析JSON列表
     */
    private List<String> parseJsonList(String json) {
        if (json == null || json.trim().isEmpty()) {
            return new ArrayList<>();
        }
        
        try {
            return gson.fromJson(json, List.class);
        } catch (Exception e) {
            log.warn("Failed to parse JSON list: {}", json, e);
            return new ArrayList<>();
        }
    }
}

